﻿// -------------------------------------------------------------------------------------
// <copyright file="TradeNOMaker.cs" company="Slwy Enterprise">
//     Copyright (c) Slwy Enterprise. All rights reserved.
// </copyright>
// <date>2016-11-22 10:28:30</date>
// <Author>lilei</Author>
// Last Modified By : lilei
// --------------------------------------------------------------------------------------

namespace Slwy.KeyIDMaker
{
    using System;
    using System.Collections.Generic;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading;

    using Slwy.Utility.ConfigurManager;

    /// <summary>
    /// 交易号生成
    /// </summary>
    public class TradeNOMaker
    { 
        /// <summary>
        /// 锁对象
        /// </summary>
        private static object lockObj = new object();

        /// <summary>
        /// 保存最近50个KeyID队列
        /// </summary>
        private static Queue<string> keyIDQueue = new Queue<string>();

        /// <summary>
        /// 队列最大数目
        /// </summary>
        private static int queueCount = 50;

        /// <summary>
        /// 创建交易流水号(TD)
        /// </summary>
        /// <returns>交易流水号</returns>
        public static string BuildTradeNumber()
        {
            return string.Format("TD{0}", NewKeyID());
        }

        /// <summary>
        /// 创建退交易批次号(RT)
        /// </summary>
        /// <returns>退交易批次号</returns>
        public static string BuilderRefundTradeNumber()
        {
            return string.Format("RT{0}", NewKeyID());
        }

        /// <summary>
        /// 创建充值流水号(R)
        /// </summary>
        /// <returns>充值流水号</returns>
        public static string BuilderRechargeNumber()
        {
            return string.Format("R{0}", NewKeyID());
        }

        /// <summary>
        /// 创建转账流水号(TF)
        /// </summary>
        /// <returns>转账流水号</returns>
        public static string BuilderTransfersNumber()
        {
            return string.Format("TF{0}", NewKeyID());
        }

        /// <summary>
        /// 创建提现订单号(WO)
        /// </summary>
        /// <returns>提现订单号</returns>
        public static string BuilderWithdrawOrderNumber()
        {
            return string.Format("WO{0}", NewKeyID());
        }

        /// <summary>
        /// 创建提现流水号(W)
        /// </summary>
        /// <returns>提现流水号</returns>
        public static string BuilderWithdrawNumber()
        {
            return string.Format("W{0}", NewKeyID());
        }

        /// <summary>
        /// 创建分润批次号(S)
        /// </summary>
        /// <returns>分润批次号</returns>
        public static string BuilderShareNumber()
        {
            return string.Format("S{0}", NewKeyID());
        }

        /// <summary>
        /// 生成KeyID
        /// </summary>
        /// <returns>KeyID</returns>
        private static string NewKeyID()
        {
            Monitor.Enter(lockObj);
            string resKeyId = string.Empty;
            StringBuilder sb = new StringBuilder();

            //当前时间
            sb.Append(DateTime.Now.ToString("yyMMddHHmmssfff"));

            var keyIdMaker = new ConfigurHalder().GetAppOptions<MKeyIdMaker>("KeyIDMarkSetting");

            ////机器码（读文件）
            sb.Append(keyIdMaker.MachineNo);

            byte[] bytes = new byte[4];
            var rng = new RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            int ranNum = BitConverter.ToInt32(bytes, 0);
            Random random = new Random(ranNum);
            ranNum = random.Next(1000, 9999);

            ////随机数
            sb.Append(ranNum);

            ////队列中包含就重新生成
            if (keyIDQueue.Contains(sb.ToString()))
            {
                resKeyId = TradeNOMaker.NewKeyID();
            }
            else
            {
                resKeyId = sb.ToString();
            }

            keyIDQueue.Enqueue(resKeyId);

            if (keyIDQueue.Count > queueCount)
            {
                keyIDQueue.Dequeue();
            }

            Monitor.Exit(lockObj);

            return resKeyId;
        }
    }
}
